
#import "WW3DAxes.h"
#import "RIBTransformBegin.h"
#import "RIBScale.h"
#import "RIBSphere.h"
#import "RIBTransformEnd.h"
#import "WWSample.h"
#import "WWEveParser.h"
#import "WW3DAttributeState.h"

@implementation WW3DAxes

+ initialize { return [WW3DAxes setVersion:1], self; }

- initWithShape:newShape
{
  id  obj;


  [super init];

  myShape = newShape;
  ribCommandList  = [[RIBCommandList alloc] init];

  // AttributeBegin, Color 0 0 1, Cylinder, Rotate -90 1 0 0, Color 0 1 0, Cylinder, Rotate 90 0 1 0, Color 1 0 0, Cylinder, AttributeEnd
  // stick them in backwards...
  [ribCommandList insertObject:[[[RIBAttributeEnd alloc] init] setMyShape:myShape] at:0];
  obj = [[[RIBCylinder alloc] init] 
          setRadius:.1 zMin:0.0 zMax:1.0 thetaMax:360. n:0 tokens:NULL parms:NULL archiveVector:NULL printfTypeVector:NULL printfNVector:NULL];
  [ribCommandList insertObject:[obj setMyShape:myShape] at:0]

  dirtyBoundingBox = YES;

  return self;
}

- awake
{
    [super awake];
    dirtyBoundingBox = YES;
    return self;
}


- setRIBCommandList:newRIBCommandList { ribCommandList = newRIBCommandList; return self; }
- ribCommandList { return ribCommandList; }

// see, this is potentially interesting, if a simple linear
// interpolation of my ribCommandList did not represent the appropriate
// linear interpolation of me, I could interpose some other list of
// objects.  For example, there might some discontinuity between
// this instance and "b", such as an enumerated 
// parameter (i.e. "sleepy, grumpy, happy, ecstatic") which doesn't
// have an obvious interpolation.  
// In the case of this simple composite object, however, 
// it is true that simply interpolating my ribCommandList is enough.
- lerpWith:b by:(float)uValue
{
   return self;
}

- lerpSelfWith:b by:(float)uValue
{
   return self;
}

- (BOOL)isLerpable { return NO; }  // heck, I never change!

- (BOOL)pushesOrPopsCTM { return NO; }
- (BOOL)pushesCTM { return NO; }
- (BOOL)popsCTM { return NO; }

- free
{
    [ribCommandList free];
    return [super free];
}

- (BOOL)hasBoundingBox		{ return YES; }
- (BOOL)isMotionBlurrable	{ return NO; }
- (BOOL)isCompoundCommand	{ return YES; }

- setBoundingBox:(RtBound *)newBoundingBox
{
    N3D_CopyBound(*newBoundingBox, boundingBox);
    return self;
}

- calculateBoundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime  
{  
    dirtyBoundingBox = NO;
    return [self setBoundingBox:[ribCommandList boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]];
}

- (RtBound *)boundingBoxStartingAt:(RtFloat)intervalStartTime endingAt:(RtFloat)intervalEndTime
{ 
   if (dirtyBoundingBox) 
   {  [self calculateBoundingBoxStartingAt:intervalStartTime endingAt:intervalEndTime];
   }
   return &boundingBox; 
}

- (float)lastSampleIsAt { return 0.0; }

- (unsigned long int)maxSampleBandwidth { return [ribCommandList maxSampleBandwidth]; }

- setMyShape:shape
{
    myShape = shape;
    return self;
}

- shape
{
    return myShape;
}

- renderMaps:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime usingStream:(NXStream *)ns
{
    return self;
}

- renderMaps:(WW3DCamera *)camera usingStream:(NXStream *)ns
{
    return self;
}

- renderMaps:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return self;
}

- renderMaps:(WW3DCamera *)camera
{
    return self;
}

- renderSelfAsBox:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return [ribCommandList renderSelfAsBox:camera
			   startingAt:shutterOpenTime
			   endingAt:shutterCloseTime];
}

- renderSelf:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return [ribCommandList renderSelf:camera
			   startingAt:shutterOpenTime
			   endingAt:shutterCloseTime];
}

- renderSelf:(WW3DCamera *)camera
{
    return [ribCommandList renderSelf:camera];
}

- preRenderSelf:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return [ribCommandList preRenderSelf:camera
			   startingAt:shutterOpenTime
			   endingAt:shutterCloseTime];
}

- preRenderSelf:(WW3DCamera *)camera
{
    return [ribCommandList preRenderSelf:camera];
}

- transformCTM:(WW3DAttributeState *)attributeState
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime 
{
    return [ribCommandList transformCTM:attributeState
                           startingAt:shutterOpenTime
			   endingAt:shutterCloseTime]; 
}

// methods to make me look like a compound command:
- (int)count {  return [ribCommandList count]; }
- objectAt:(int)i {  return [ribCommandList objectAt:i]; }


// WavesWorld archiving:
// writeEve:(NXStream *)stream
// writeScene:(NXStream *)stream

- writeEve:(NXStream *)stream atTabLevel:(int)tab
{
    int  i;
    
    for (i = 0; i < tab; i++) {
	NXPrintf(stream, "\t");
    }
    NXPrintf(stream, "WW3DAxes %f %f %f %f", radius, zMin, zMax, thetaMax, yScale);
    return self;
}

- writeScene:(NXStream *)stream atTabLevel:(int)tab
{
    int  i;
    
    for (i = 0; i < tab; i++) {
	NXPrintf(stream, "\t");
    }
    NXPrintf(stream, "WW3DAxes %f %f %f %f", radius, zMin, zMax, thetaMax, yScale);
    return self;
}

- write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }

   NXPrintf(stream, "startShape %s; ", [[self class] name]);
   // need tab
   // need index (position in current list)
   NXPrintf(stream, 
	    "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n", 
            tab, index); 
   NXPrintf(stream, "  EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
   [self writeEve:stream atTabLevel:tab];
   NXPrintf(stream, "} left;}\n");
  NXPrintf(stream, "endShape;\n");

  return self;
}

- writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "# ");
   [self writeEve:stream atTabLevel:tab];
   NXPrintf(stream, "\n");

   return [ribCommandList writeInventorAtTime:currentTime to:stream atTabLevel:tab];
}

#define typeVector "@ffff"
#define typeValues &ribCommandList, &radius, &zMin, &zMax, &yScale

- read:(NXTypedStream *)stream 
{
    int version;
    
    [super read:stream];
    version = NXTypedStreamClassVersion(stream,"WW3DAxes");
    if (version == 0) NXReadTypes(stream, "i", &version), version = 1;
    if (version == 1)
    {  NXReadTypes(stream, typeVector, typeValues);
       NXReadArray(stream, "f", 6, boundingBox);
       myShape = NXReadObject(stream);
       xScale = zScale = 1./sqrt((double)yScale);
    }

    return self;
}

- write:(NXTypedStream *)stream 
{
    [super write:stream];
    NXWriteTypes(stream, typeVector, typeValues);
    NXWriteArray(stream, "f", 6, boundingBox);
    NXWriteObjectReference(stream, myShape);
    return self;
}

- (BOOL)theSameAs:otherRIBCommand
{
  if (radius != [otherRIBCommand radius])
  {  return NO;
  }
  if (yScale != [otherRIBCommand yScale])
  {  return NO;
  }
  if (zMin != [otherRIBCommand zMin])
  {  return NO;
  }
  if (zMax != [otherRIBCommand zMax])
  {  return NO;
  }
  if (thetaMax != [otherRIBCommand thetaMax])
  {  return NO;
  }
  return YES;
}

- (BOOL)isMoot
{
  return NO;
}

- (BOOL)isMootStartingAt:(float)startTime endingAt:(float)endTime  {  return [self isMoot];  }

// boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
- class { return [super class]; }

@end
